/*-----------------------------------------------------------------------------
 *
 *  event.c - Event module 
 *
 *    Copyright (c) 1998, SaberNet.net - All rights reserved
 *
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU General Public License
 *    as published by the Free Software Foundation; either version 2
 *    of the License, or (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307
 *
 *  $Id: event.c,v 1.1.1.1 2001/11/28 05:25:03 sabernet Exp $
 *
 *  Revision history:
 *    06-Sep-2006  EYC  Removed support for secondary syslog host
 *    01-Dec-1999  JRR  Removed superfluous gethostbyaddr
 *    28-Sep-1999  JRR  Added support for secondary syslog host
 *    18-Aug-1998  JRR  Module completed
 *
 *----------------------------------------------------------------------------*/
#include <stdio.h>
#include <winsock2.h>
//#include <mstcpip.h>
#include "event.h"

/*-------------------------------[ static data ]------------------------------*/
#define SO_CONNECT_TIME 28684
#define SYSLOG_NAME         "syslog"
#define SYSLOG_PORT         514
#define REG_BUFFER_LEN      1024
#define SYSLOG_REG_KEY_0    "Syslog"
#define SYSLOG_REG_KEY_1    "Syslog1"

static SOCKET   			 sock;
static	WSADATA  			 wsaData;
static const char *syslog_host(char *host, int len, char *regkey);

int event_init()
{
	struct sockaddr_in   server;
	struct servent      *serv;
    int                  port = htons(SYSLOG_PORT);

	char *server_name;

	// Init hostname  for syslog from registry..
	static char host[2][NTSL_SYS_LEN] = { "", "" };

#ifdef _DEBUG
    	printf("Initiating syslog socket\n");
#endif

	if (host[0][0] == 0)
	{
		syslog_host(host[0], NTSL_SYS_LEN, SYSLOG_REG_KEY_0);
		syslog_host(host[1], NTSL_SYS_LEN, SYSLOG_REG_KEY_1);

		if (host[0][0] == 0) 
			ntsl_die(NTSL_ERROR_SYSLOG_CONFIG);
	}
	server_name=host[0];


	//if ( (event == NULL) || (server_name == NULL) || (server_name[0] == 0) )
	if ((server_name == NULL) || (server_name[0] == 0) )
		return(-1);

	memset(&server, 0, sizeof(server));


    if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR)
    {
        ntsl_log_error(NTSL_ERROR_WSASTARTUP, WSAGetLastError());
        WSACleanup();
        return(-1);
    }

    /* lookup service port from services file */
    if ((serv = getservbyname(SYSLOG_NAME, "tcp")) != NULL)
    {
       port = serv->s_port;
    }

	if (isalpha(server_name[0])) 
	{   
		struct hostent *hp = gethostbyname(server_name);
		if (hp != NULL) 
			memcpy(&(server.sin_addr),hp->h_addr,hp->h_length);
	}
	else  
	{ 
		server.sin_addr.s_addr = inet_addr(server_name);
	}

	if (server.sin_addr.s_addr == 0) 
	{
		WSACleanup();
		return(-1);
	}
	
	/* setup sockaddr_in structure */
	server.sin_family = AF_INET;
	server.sin_port   = port;

	/* open socket */
	/* Ey-Hack */
	/*sock = socket(AF_INET, SOCK_DGRAM, 0);*/
	sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        /* end Ey-Hack */
	if (sock <= 0) 
	{
		ntsl_log_error(NTSL_ERROR_SOCKET_INIT, WSAGetLastError());
		WSACleanup();
		return -1;
	}

	/* connect to syslog host */
	if (connect(sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) 
	{
        ntsl_log_error(NTSL_ERROR_SOCKET_SEND, WSAGetLastError());
        WSACleanup();
		return -1;
	} 
	return 1;

	/* put it in _die, _disconnect, or _stop or sth */
        //closesocket(sock);
	//WSACleanup();
	//end.



};

/*------------------------------[ event_output ]------------------------------
 *  Output the event
 *
 *  Parameters:
 *		event		event to format
 *		fp			file pointer
 *
 *  Return value:
 *		success		(0)
 *		failure		(-1)
 *
 *----------------------------------------------------------------------------*/
static int _event_output(ntsl_event *event)
{
	char				 buffer[NTSL_EVENT_FORMAT_LEN];
		int					 len;
		int					bytessent;
		int optVal;
	    int optLen = sizeof(int);
		fd_set FAR* readfds;
		fd_set FAR* writefds;
		fd_set FAR* errfds;
		int new_conns;
		HANDLE Event;
		struct tcp_keepalive {
			 u_long onoff;
			 u_long keepalivetime;
			 u_long keepaliveinterval;
		} tka;
		DWORD dwRet, dwSize;
		LPWSANETWORKEVENTS NetworkEvents; 
		
		

	len = _snprintf0(buffer, NTSL_EVENT_FORMAT_LEN, "<9>%s %s%s%s%s\n", event->date,
				event->source, event->etype, (event->msg[0] == ':' ? "" : " "), event->msg);


	/* Verify that sock is fine and dandy */
	
	if (getsockopt(sock,SOL_SOCKET,SO_CONNECT_TIME, (char*)&optVal, &optLen) != SOCKET_ERROR)
		printf("SockOpt Value: %ld, SO_CONNECT_TIME:%d\n", optVal,SO_CONNECT_TIME);
	if (optVal>3000) {
		printf("Reseting connection, a co\n");
		closesocket(sock);
	    WSACleanup();
		sock=0;
		event_init();
	};

	/* if connect_time > 12h, restart connection ;) */
	if (sock==INVALID_SOCKET) 
		printf("Invalid Socket\n");
	 if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, &optLen) != SOCKET_ERROR) {
    printf("SO_KEEPALIVE Value: %ld\n", optVal);
  }

	optVal=5;
  if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, optLen) != SOCKET_ERROR) {
    printf("Set SO_KEEPALIVE: ON\n");
  }
  // ....
//     WSAIoctl(sock,ControlCode,
	//WSAAsyncSelect(sock,Event,uintwMSG,longIEvent);

	

	//Event = WSACreateEvent(); 
    Event = CreateEvent (NULL, TRUE, FALSE, "NetworkEvent");
	if (Event){
		//CloseHandle (hEvents[0]);
		//std::cerr << "Can't create event! Thread shutdown!\n";
		//return -2;
	}


	if (Event != WSA_INVALID_EVENT) { printf("VALID event\n");} ;

	WSAEventSelect(sock, Event, FD_READ|FD_CLOSE); 
	

    WSAEnumNetworkEvents(sock,Event,NetworkEvents);
//	WSAEnumNetworkEvents(sock, Event, &NetworkEvents); 
	if (NetworkEvents->lNetworkEvents & FD_CLOSE) 
	{ 
	printf("CLOSED EVENT\n");
	} 

	if (NetworkEvents->lNetworkEvents & FD_READ) 
	{ 
	printf("READ EVENT\n");
	} 

	//if ((Sent = send(Socket, Buffer, bSize, NULL)) < 0) 
	//( WSAGetLastError() == WSAEWOULDBLOCK ) return OK; 
    //if (! Sent) return COMPLETE; 
	/*  
*/
  // end .... (wsaselect)

  if (getsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&optVal, &optLen) != SOCKET_ERROR) {
    printf("SO_KEEPALIVE Value: %ld\n", optVal);
  }

  if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&optVal, &optLen) != SOCKET_ERROR) {
    printf("SO_ERROR Value: %ld\n", optVal);
  }
	printf("GetLastErr: %d\n",WSAGetLastError());

	FD_ZERO(&readfds);FD_ZERO(&writefds);FD_ZERO(&errfds);
	FD_SET(sock,&readfds);
	FD_SET(sock,&writefds);
	FD_SET(sock,&errfds);
	new_conns=select(12,readfds,writefds,errfds,NULL);
	printf("New conns: %d, \n",new_conns);
/*
keep-alive!

*/
	//WSAIoctl(sock,SIO_KEEPALIVE_VALS,lpvoidIPVINBUFFER,dwordCBINBUFFER,lpvoidlpvoutbuffer,dwordcboutbuffer,lpwordbytesreturned,lpoverlapped,NULL);
//	tka.onoff=1;tka.keepalivetime=10;tka.keepaliveinterval=10;
//	dwRet=WSAIoctl(sock,SIO_KEEPALIVE_VALS,&tka,sizeof(tka),
//		NULL,0,&dwSize,NULL,NULL);

//	struct tcp_keepalive alive;
//	DWORD dwRet, dwSize;
//
//	dwRet = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
//		NULL, 0, reinterpret_cast<DWORD*>(&dwSize), NULL, NULL);
	if (dwRet == SOCKET_ERROR)
	{
		printf("WSAIoctl fail..\n");
		//std::cerr << "WSAIoctl fail with code " << WSAGetLastError() << "\n";
	}





	/* end verify sock */
	/* send syslog message */
	bytessent=send(sock, buffer, len, 0);
	if (bytessent == SOCKET_ERROR || len!=bytessent)
	{
#ifdef _DEBUG
    	printf("Problem sending message! trying to close the socket and stuff.. (%s)\n", buffer, len);
#endif
        ntsl_log_error(NTSL_ERROR_SOCKET_SEND, WSAGetLastError());
		closesocket(sock);
	    WSACleanup();
		sock=0;
#ifdef _DEBUG
    	printf("Problem sending message! (%s)\n", buffer, len);
#endif
        return -1;
	} 

#ifdef _DEBUG
	printf("GetLastErr: %d\n",WSAGetLastError());
	printf("Sent msg:\"%s\" %d\n(Result: %d)\n", buffer, len,bytessent);
#endif

		return(0);
}

int event_output(ntsl_event *event)
{
	int rc[2] = {-1, -1};

	if  (event == NULL) 
		return -1;

	if (sock == 0) 
		event_init();

	rc[0] = _event_output(event);//, host[0]);
	//rc[1] = _event_output(event, host[1]);

	//return(rc[0] == 0 || rc[1] == 0 ? 0 : -1);
	return(rc[0] == 0 || rc[1] == 0 ? 0 : -1);
}

static const char *syslog_host(char *host, int len, char *regkey)
{
	char		buffer[REG_BUFFER_LEN];
	HKEY		hReg;
	int32		rc;

	if (host != NULL)
	{
		while(1)    // while loop used as control structure
		{
			_snprintf0(buffer, REG_BUFFER_LEN, "SOFTWARE\\%s", DEV_NAME);
			rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_READ, &hReg);
			if (rc != ERROR_SUCCESS)
				break;
		
			rc  = RegQueryValueEx(hReg, regkey, NULL, NULL, (unsigned char*)host, &len);
			if (rc != ERROR_SUCCESS)
				break;

			break;
		}
		
		RegCloseKey(hReg);

	}

	return(host);
}


